package com.mebs.model.logistics;

import javax.persistence.*;
import java.util.Set;
import java.util.Date;
import java.util.List;
import java.util.LinkedList;

import org.jt.jet.util.JetUtils;
import static org.hibernate.proxy.HibernateProxyHelper.getClassWithoutInitializingProxy;
import com.mebs.model.WeightUnit;
import com.mebs.model.AuditInfo;
import com.mebs.model.VolumeUnit;
import com.mebs.model.inventory.*;

/**
 * Created by Sergey Prasolov, sap@jensentechnologies.com Date: Mar 7, 2006, 12:34:21 PM
 */
@Entity()
@Table(name = "STORAGE_LOT")
public class Lot {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Id")
    private Long id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "StorageId")
    private Storage storage;

    @Column(name = "Description", nullable = true, length = 1024)
    private String description;

    @Column(name = "Volume", nullable = true)
    private Double volume;

    @Column(name = "volumeUnit", nullable = true)
    private Integer volumeUnit;

    @Column(name = "Weight", nullable = true)
    private Double weight;

    @Column(name = "WeightUnit", nullable = true)
    private Integer weightUnit;

    @Column(name = "DateIn", nullable = true)
    private Date dateIn;

    @Column(name = "DateOut", nullable = true)
    private Date dateOut;

    @Column(name = "RateUsd", nullable = true)
    private Double rateUsd;

    @Column(name = "OutState", nullable = true)
    private Integer outState;

    @Column(name = "Notes", nullable = true, length = 1024)
    private String notes;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "LotId")
    @OrderBy("number")
    private Set<Box> boxes;

    @Embedded
    private AuditInfo auditInfo;

    /**
     * ********************** Getters-setters ***********************
     */

    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public String getDescription()
    {
        return description;
    }

    public void setDescription(String description)
    {
        this.description = description;
    }

    public Double getVolume()
    {
        return volume;
    }

//    @Transient
//    public Double getVolume()
//    {
//        Double boxVolume = 0.0;
//        Double bVolume = null;
//
//        if (boxes != null) {
//            for (Box b : boxes) {
//                bVolume = b.getVolume();
//                if (bVolume != null) {
//                    boxVolume += bVolume;
//                }
//            }
//        }
//
//        if (boxVolume == 0.0) {
//            boxVolume = null;
//        }
//
//        return boxVolume;
//    }

    public void setVolume(Double volume)
    {
        this.volume = volume;
    }

    public Integer getVolumeUnit()
    {
        return volumeUnit;
    }

    public void setVolumeUnit(Integer volumeUnit)
    {
        this.volumeUnit = volumeUnit;
    }

    public Double getWeight()
    {
        return weight;
    }

    public void setWeight(Double weight)
    {
        this.weight = weight;
    }

    public Date getDateIn()
    {
        return dateIn;
    }

    public void setDateIn(Date dateIn)
    {
        this.dateIn = dateIn;
    }

    public Date getDateOut()
    {
        return dateOut;
    }

    public void setDateOut(Date dateOut)
    {
        this.dateOut = dateOut;
    }

    public Double getRateUsd()
    {
        return rateUsd;
    }

    public void setRateUsd(Double rateUsd)
    {
        this.rateUsd = rateUsd;
    }

    public String getNotes()
    {
        return notes;
    }

    public void setNotes(String notes)
    {
        this.notes = notes;
    }

    public Integer getWeightUnit()
    {
        return weightUnit;
    }

    public void setWeightUnit(Integer weightUnit)
    {
        this.weightUnit = weightUnit;
    }

    public Integer getOutState()
    {
        return outState;
    }

    public void setOutState(Integer outState)
    {
        this.outState = outState;
    }

    public Set<Box> getBoxes()
    {
        return boxes;
    }

    public void setBoxes(Set<Box> boxes)
    {
        this.boxes = boxes;
    }

    public Storage getStorage()
    {
        return storage;
    }

    public void setStorage(Storage storage)
    {
        this.storage = storage;
    }

    public AuditInfo getAuditInfo()
    {
        if (this.auditInfo == null) {
            this.auditInfo = new AuditInfo();
        }
        return auditInfo;
    }

    public void setAuditInfo(AuditInfo auditInfo)
    {
        this.auditInfo = auditInfo;
    }

    @Transient
    public boolean isOrderUsed(AbstractOrder order)
    {
        if (order instanceof PurchaseOrder) {
            return isPOUsed((PurchaseOrder) order);
        } else if (order instanceof RelocationOrder) {
            return isROUsed((RelocationOrder) order);
        }
        return false;  // for a case (iav)
    }

    @Transient
    public boolean isPOUsed(PurchaseOrder po)
    {
        if (JetUtils.isEmpty(this.boxes)) return false;
        for (Box box : this.boxes) {
            if (box instanceof StructuredBox) {
                for (BoxItem boxItem : ((StructuredBox) box).getItems()) {
                    if (boxItem.getOrderItem().getOrder().equals(po)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    @Transient
    public boolean isROUsed(RelocationOrder ro)
    {
        if (JetUtils.isEmpty(this.boxes)) return false;
        for (Box box : this.boxes) {
            if (box instanceof RelocationPiece) {
                if (((RelocationPiece) box).getOrder().equals(ro)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Transient
    public List<Box> getNotPackedBoxes()
    {
        List<Box> notPackedBoxes = new LinkedList<Box>();

        for (Box b : this.boxes) {
            if (b.getOverpackedBox() == null) {
                notPackedBoxes.add(b);
            }
        }

        return notPackedBoxes;
    }

    @Transient
    public boolean hasItem(Object item)
    {
        if (item instanceof RelocationPiece) {
            return this.hasPiece((RelocationPiece) item);
        }

        return false;
    }

    @Transient
    private boolean hasPiece(RelocationPiece piece)
    {
        if (JetUtils.isEmpty(this.boxes)) {
            return false;
        }

        return this.boxes.contains(piece);
    }

    @Transient
    public boolean isPiece(Box item)
    {
        return (item instanceof RelocationPiece);
    }

    @Transient
    public String getWeightUnitString()
    {
        return weightUnit != null ? WeightUnit.getObjectByType(weightUnit).getName() : "";
    }

    @Transient
    public String getOutStateString()
    {
        return outState != null ? StorageOutState.getObjectByType(outState).getName() : "";
    }

    @Transient
    public boolean isDeletable()
    {
        return JetUtils.isEmpty(this.boxes);
    }

    @Override
    public String toString()
    {
        return this.description;
    }

/*
    @Transient
    @Deprecated
    public Integer getBoxedQuantity(BoxSubItem subItem)
    {
        if (JetUtils.isEmpty(boxes)) return 0;

        int qty = 0;

        for (Box box : getNotPackedBoxes()) {
            if (box instanceof StructuredBox)
                qty += ((StructuredBox) box).getItemQuantity(subItem);
            else if (box instanceof OverpackedBox)
                qty += ((OverpackedBox) box).getItemQuantity(subItem);
        }

        return qty;
    }

    @Transient
    @Deprecated
    public Integer getBoxedQuantity(OrderItem orderItem)
    {
        if (JetUtils.isEmpty(boxes)) return 0;

        int qty = 0;
        for (Box box : getNotPackedBoxes()) {
            if (box instanceof StructuredBox) {
                qty += ((StructuredBox) box).getItemQuantity(orderItem);
            } else if (box instanceof OverpackedBox) {
                qty += ((OverpackedBox) box).getItemQuantity(orderItem);
            }
        }

        return qty;
    }
*/

    @Override
    public int hashCode()
    {
        if (id == null) return super.hashCode();
        return id.hashCode();
    }

    @Override
    public boolean equals(Object o)
    {
        if (o == null) return false;
        if (this == o) return true;
        if (id == null) return false;
        if (getClassWithoutInitializingProxy(this) != getClassWithoutInitializingProxy(o))
            return false;
        final Lot that = (Lot) o;
        return id.equals(that.getId());
    }

    @Transient
    public Double getWeightCoef()
    {
        if (weightUnit == null) {
            return null;
        }

        return WeightUnit.getObjectByType(weightUnit).getCoef();
    }

    @Transient
    public Double getVolumeCoef()
    {
        if (volumeUnit == null) {
            return null;
        }

        return VolumeUnit.getObjectByType(volumeUnit).getCoef();
    }

    @Transient
    public String getVolumeUnitString()
    {
        return volumeUnit != null ? VolumeUnit.getObjectByType(volumeUnit).getName() : "";
        //return "";
    }
}
